package com.liyy.platform.config;

/**
 * Created by liyy on 2018/3/22.
 */
import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.MatchAllQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PreDestroy;
import java.io.IOException;
import java.util.concurrent.TimeUnit;

// Java客户端生成工厂
@Configuration
public class RestClientFactory{
    private static final String HOST = "127.0.0.1";
    private static final int PORT = 9200;
    private static final String SCHEMA = "http";
    private static final int CONNECT_TIME_OUT = 1000;
    private static final int SOCKET_TIME_OUT = 30000;
    private static final int CONNECTION_REQUEST_TIME_OUT = 500;
    private static final int MAX_CONNECT_NUM = 100;
    private static final int MAX_CONNECT_PER_ROUTE = 100;
    private static HttpHost HTTP_HOST = new HttpHost(HOST,PORT,SCHEMA);
    private static boolean uniqueConnectTimeConfig = false;
    private static boolean uniqueConnectNumConfig = true;
    private static RestClientBuilder builder;
    private static RestClient restClient;
    private static RestHighLevelClient restHighLevelClient;

    static {
        init();
    }

    public static void init(){
        System.out.println("实例client开始实例化......");
        builder = RestClient.builder(HTTP_HOST);
        if(uniqueConnectTimeConfig){
            setConnectTimeOutConfig();
        }
        if(uniqueConnectNumConfig){
            setMutiConnectConfig();
        }
        restClient = builder.build();
        restHighLevelClient = new RestHighLevelClient(builder);
    }

    // 主要关于异步httpclient的连接延时配置
    public static void setConnectTimeOutConfig(){
        builder.setRequestConfigCallback(new RestClientBuilder.RequestConfigCallback() {
            @Override
            public RequestConfig.Builder customizeRequestConfig(RequestConfig.Builder builder) {
                builder.setConnectTimeout(CONNECT_TIME_OUT);
                builder.setSocketTimeout(SOCKET_TIME_OUT);
                builder.setConnectionRequestTimeout(CONNECTION_REQUEST_TIME_OUT);
                return builder;
            }
        });
    }

    /**
     *    主要关于异步httpclient的连接数配置
     */
    public static void setMutiConnectConfig(){
        builder.setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
            @Override
            public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpAsyncClientBuilder) {
                httpAsyncClientBuilder.setMaxConnTotal(MAX_CONNECT_NUM);
                httpAsyncClientBuilder.setMaxConnPerRoute(MAX_CONNECT_PER_ROUTE);
                return httpAsyncClientBuilder;
            }
        });
    }

    public static RestClient getClient(){
        return restClient;
    }

    @Bean(name = "client")
    public static RestHighLevelClient getHighLevelClient(){
        if(restHighLevelClient==null){
            init();
        }
        return restHighLevelClient;
    }

    //在IOC销毁client对象之前，就关闭client对象所持有的连接
    @PreDestroy
    public void close() {
        System.out.println("client实例准备开始关闭连接......");
        if (restHighLevelClient != null) {
            try {
                restHighLevelClient.close();
                System.out.println("client实例连接已正常关闭。");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     *  封装RestHighLevelClient根据指定ID添加方法
     */
    public static IndexResponse add(String index, String type, String id, String jsonSource)
            {
                // 构建请求
                IndexRequest request = new IndexRequest(index, type, id);
                // 将保存数据以JSON格式关联到请求
                request.source(jsonSource, XContentType.JSON);
                // Java客户端发起保存数据请求
                IndexResponse response = null;
                try {
                    response = RestClientFactory.getHighLevelClient().index(request);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                // 等待结果
                System.out.println(response);
                return response;
    }

    /**
     *  封装RestHighLevelClient根据指定ID删除方法
     */
    public static DeleteResponse delete(String index, String type, String id)
    {
        // 构建请求
        DeleteRequest deleteRequest = new DeleteRequest(index,type,id);
        // Java客户端发起保存数据请求
        DeleteResponse response = null;
        try {
            response = RestClientFactory.getHighLevelClient().delete(deleteRequest);
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 等待结果
        System.out.println(response);
        return response;
    }

    public static SearchResponse getAllList(String INDEX,String TYPE,int pageNo, int pageSize){
        RestHighLevelClient client = RestClientFactory.getHighLevelClient();
        // 这个sourcebuilder就类似于查询语句中最外层的部分。包括查询分页的起始，
        // 查询语句的核心，查询结果的排序，查询结果截取部分返回等一系列配置
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        // 结果开始处
        sourceBuilder.from((pageNo-1)*pageSize);
        // 查询结果终止处
        sourceBuilder.size(pageSize);
        // 查询的等待时间
        sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
        //开始拼接查询语句
        MatchAllQueryBuilder matchAllQuery= QueryBuilders.matchAllQuery();
        // 排序
        FieldSortBuilder fsb = SortBuilders.fieldSort("_score");
        fsb.order(SortOrder.DESC);
        sourceBuilder.sort(fsb);

        sourceBuilder.query(matchAllQuery);
        System.out.println(sourceBuilder);
        //指定更新的索引库和类型
        SearchRequest searchRequest = new SearchRequest(INDEX);
        searchRequest.types(TYPE);
        searchRequest.source(sourceBuilder);
        try {
            return client.search(searchRequest);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}